﻿using System;
using System.Text;

namespace ProjectEuler
{
    internal static class Common
    {
        public static bool IsPrime(long number)
        {
            if (number < 2) return false;
            if (number < 4) return true;
            if (number % 2 == 0) return false;
            if (number < 9) return true;
            if (number % 3 == 0) return false;

            var r = Math.Floor(Math.Sqrt(number));
            var f = 5;

            while (f <= r)
            {
                if (number % f == 0) return false;
                if (number % (f+2) == 0) return false;
                f += 6;
            }

            return true;
        }

        public static string MultBySingleDigit(string num, int digit)
        {
            var sb = new StringBuilder(num);

            var kratoumeno = 0;
            for (var i = num.Length - 1; i >= 0; i--)
            {
                var mul = Int32.Parse(sb[i].ToString()) * digit + kratoumeno;
                kratoumeno = mul / 10;
                sb[i] = (mul % 10).ToString()[0];
            }

            var result = kratoumeno > 0 ? kratoumeno + sb.ToString() : sb.ToString();
            return result;
        }

        public static string Mult(string num, string num1)
        {
            var partialmults = new string[num1.Length];

            for (var i = num1.Length-1; i >= 0; i--)
            {
                partialmults[num1.Length - i - 1] = MultBySingleDigit(num, Int32.Parse(num1[i].ToString()));
            }

            var sb = new StringBuilder(partialmults[0]);
            for (var i = 1; i < partialmults.Length; i++)
            {
                var partMult = partialmults[i];
                var kratoumeno = 0;
                for (var j = 0; j < partMult.Length; j++)
                {
                    var n1 = sb.Length - i - 1 - j >= 0 ? Int32.Parse(sb[sb.Length - i - 1 - j].ToString()) : 0;
                    var n2 = Int32.Parse(partMult[partMult.Length - 1 - j].ToString());
                    var sum = n1 + n2 + kratoumeno;

                    kratoumeno = sum/10;
                    var c = (sum%10).ToString()[0];
                    if (sb.Length - i - 1 - j > -1)
                        sb[sb.Length - i - 1 - j] = c;
                    else
                    {
                        sb = new StringBuilder(c + sb.ToString());
                    }

                }
                if (kratoumeno > 0)
                {
                    sb = new StringBuilder(kratoumeno + sb.ToString());
                }
            }

            return sb.ToString();
        }

        public static string FactorialAsString(int num)
        {
            var fact = "2";
            for (var i = 3; i <= num; i++)
            {
                fact = Mult(fact, i.ToString());
            }

            return fact;
        }

        public static int FactorialAsNum(int num)
        {
            if (num == 0 || num == 1 || num == 2) return num;

            var fact = 2;
            for (var i = 3; i <= num; i++)
            {
                fact = fact * i;
            }

            return fact;
        }

        public static int SumOfProperDivisors(int num)
        {
            int sum = 0;
            for (var i = num / 2; i > 0; i--)
            {
                if (num % i == 0)
                    sum += i;
            }

            return sum;
        }

        public static bool IsAbundant(int num)
        {
            int sum = 0;
            for (var i = num / 2; i > 0; i--)
            {
                if (num % i == 0)
                {
                    sum += i;
                    if (sum > num)
                        return true;
                }
            }

            return false;
        }

        public static string Add(string num1, string num2)
        {
            var maxLen = Math.Max(num1.Length, num2.Length);
            var minLen = Math.Min(num1.Length, num2.Length);
            
            StringBuilder sb;
            sb = maxLen == num1.Length ? new StringBuilder(num1) : new StringBuilder(num2);

            var kratoumeno = 0;
            for (int i = 0; i < minLen; i++)
            {
                var c = Int32.Parse(num1[num1.Length - 1 - i].ToString()) + Int32.Parse(num2[num2.Length - 1 - i].ToString()) + kratoumeno;
                kratoumeno = c/10;
                var ypoloipo = c%10;
                sb[maxLen - 1 - i] = ypoloipo.ToString()[0];
            }

            if (kratoumeno > 0)
            {
                if (maxLen > minLen)
                {
                    var c = Int32.Parse(sb[maxLen - 1 - minLen].ToString()) + kratoumeno;

                    var ypoloipo = c % 10;
                    sb[maxLen - 1 - minLen] = ypoloipo.ToString()[0];

                    var y = c / 10;
                    if (y > 0)
                    {
                        sb = new StringBuilder(y + sb.ToString());
                    }
                }
                else
                {
                    sb = new StringBuilder(kratoumeno + sb.ToString());
                }
            }

            return sb.ToString();
        }
    }
}